﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.SqlServerCe;
using System.IO;
using System.Linq;
using CAION2.Classes;
using CAION2.ViewModels;
using Microsoft.Win32;

namespace CAION2.Models
{
    public static class DataModel
    {
        internal static readonly string WorkDirectory;
        public static readonly string IconsDirectory;
        private static readonly string ConnectionString = @"Data Source=|DataDirectory|\Data\Data.sdf";
        internal static readonly string EngFix;

        public static readonly List<string> TableList; 

        static DataModel()
        {
            WorkDirectory = Directory.GetCurrentDirectory();
            IconsDirectory = WorkDirectory + @"\Icons\";

            //ConnectionString = ConnectionString.Replace("|DataDirectory|", WorkDirectory);
            AppDomain.CurrentDomain.SetData("DataDirectory", WorkDirectory);
            
            EngFix = ClassConfiguration.GetValue("ItemsLanguage").ToString() == "ru" ? "" : "_en";

            TableList = new List<string>
                        {
                            "Allitems_Weapons",
                            "Allitems_Torsos",
                            "Allitems_Legs",
                            "Allitems_Shoulders",
                            "Allitems_Gloves",
                            "Allitems_Foots",
                            "Allitems_Ears",
                            "Allitems_Fingers",
                            "Allitems_Heads",
                            "Allitems_Necks",
                            "Allitems_Waists",
                            "Allitems_Wings"
                        };
        }

        public static ObservableCollection<Recipe> GetRecipesList(string tableName)
        {
            DataTable table = GetTable(tableName, "id, item_type, product_translate" + EngFix + " AS product_translate, combo2_product_translate" + EngFix + 
                                                              " AS combo2_translate," +
                                                              " level, required_skillpoint, " + 
                                                              "product, combo1_product, combo2_product, combo3_product, combo4_product, " +
                                                              "qualification_race", 
                                                              UpdateConditionForRecipesList());

            ObservableCollection<Recipe> recipesList = new ObservableCollection<Recipe>
                (table.AsEnumerable().Select(i => new Recipe
                {
                    Id = Convert.ToString(i["id"]),
                    Translate = Convert.ToString(i["product_translate"]),
                    Translate2 = Convert.ToString(i["combo2_translate"]),
                    Type = Convert.ToString(i["item_type"]),
                    Product = Convert.ToString(i["product"]),
                    Combo1 = Convert.ToString(i["combo1_product"]),
                    Combo2 = Convert.ToString(i["combo2_product"]),
                    Combo3 = Convert.ToString(i["combo3_product"]),
                    Combo4 = Convert.ToString(i["combo4_product"]),
                    CharacterLevel = Convert.ToByte(i["level"]),
                    RecipeLevel = Convert.ToInt16(i["required_skillpoint"]),
                    Faction = Convert.ToString(i["qualification_race"]),
                    Quality = Convert.ToString(i["item_type"])
                }));

            return recipesList;
        }

        private static string UpdateConditionForRecipesList()
        {
            string condition = "";

            if (ClassConfiguration.GetInt32("RecipesMinLevel") > 1)
            {
                condition = string.Format("(required_skillpoint >= {0})", ClassConfiguration.GetInt32("RecipesMinLevel"));
            }
            if (ClassConfiguration.GetInt32("RecipesMaxLevel") < ClassConfiguration.RecipesMaximumLevel)
            {
                condition = condition.Length > 0
                    ? string.Format("(required_skillpoint BETWEEN {0} AND {1})", ClassConfiguration.GetInt32("RecipesMinLevel"), ClassConfiguration.GetInt32("RecipesMaxLevel"))
                    : String.Format("(required_skillpoint <= {0})", ClassConfiguration.GetInt32("RecipesMaxLevel"));
            }


            string newCondition = "";
            if (ClassConfiguration.GetInt32("CharacterMinLevel") > 1)
            {
                newCondition = string.Format("(level >= {0})", ClassConfiguration.GetInt32("CharacterMinLevel"));
            }
            if (ClassConfiguration.GetInt32("CharacterMaxLevel") < ClassConfiguration.CharacterMaximumLevel)
            {
                newCondition = newCondition.Length > 0
                    ? string.Format("(level BETWEEN {0} AND {1})", ClassConfiguration.GetInt32("CharacterMinLevel"), ClassConfiguration.GetInt32("CharacterMaxLevel"))
                    : String.Format("(level <= {0})", ClassConfiguration.GetInt32("CharacterMaxLevel"));
            }
            condition = UnionTwoCondition(condition, newCondition);


            List<bool> fractions = new List<bool>
                {
                    ClassConfiguration.GetBool("RecipesRaceE"),
                    ClassConfiguration.GetBool("RecipesRaceA")
                };

            if (fractions[0] != fractions[1])
            {
                if (fractions[0]) newCondition = string.Format("(qualification_race LIKE 'pc_light')");
                if (fractions[1]) newCondition = string.Format("(qualification_race LIKE 'pc_dark')");
            }
            condition = UnionTwoCondition(condition, newCondition);


            List<bool> qualities = new List<bool>
                {
                    ClassConfiguration.GetBool("RecipesQualityCommon"),
                    ClassConfiguration.GetBool("RecipesQualityRare"),
                    ClassConfiguration.GetBool("RecipesQualityLegend"),
                    ClassConfiguration.GetBool("RecipesQualityUnique"),
                    ClassConfiguration.GetBool("RecipesQualityEpic"),
                    ClassConfiguration.GetBool("RecipesQualityMythic")
                };

            bool allSameTrue = !qualities.Select(item => item).Distinct().Skip(1).Any();
            bool allSameFalse = !qualities.Select(item => item == false).Distinct().Skip(1).Any();
            
            if (!allSameTrue && !allSameFalse)
            {
                string qList = "(";
                if (qualities[0]) qList += "'common',";
                if (qualities[1]) qList += "'rare',";
                if (qualities[2]) qList += "'legend',";
                if (qualities[3]) qList += "'unique',";
                if (qualities[4]) qList += "'epic',";
                if (qualities[5]) qList += "'mythic'";

                if (qList.EndsWith(",")) qList = qList.Substring(0, qList.Length - 1);
                qList += ")";
                newCondition = string.Format("(item_type IN {0})", qList);
            }
            condition = UnionTwoCondition(condition, newCondition);

            return condition;
        }

        private static string UnionTwoCondition(string mainCondition, string addinCondition)
        {
            if (string.IsNullOrEmpty(addinCondition)) return mainCondition;

            if (mainCondition.Length > 0)
            {
                mainCondition += " AND " + addinCondition;
            }
            else
            {
                mainCondition = addinCondition;
            }

            return mainCondition;
        }

        public static DataRow GetRowAtName(string tableName, string filterValue, string fields = "*", string filterField = "name")
        {
            string condition = filterField + " = '" + filterValue + "'";
            DataTable table = GetTable(tableName, fields, condition, 1);
            
            return table.Rows.Count > 0 ? table.Rows[0] : table.NewRow();
        }
        public static DataRow GetRow(string tableName, string conditions, string fields = "*", int topCount = 0)
        {
            DataTable table = GetTable(tableName, fields, conditions, topCount);
            return table.Rows.Count > 0 ? table.Rows[0] : table.NewRow();
        }

        public static DataTable GetTable(string tableName, string fields, string conditions, int topCount = 0)
        {
            if (string.IsNullOrEmpty(fields)) fields = "*";

            string selectCommand = string.Format(@"SELECT {0} {1} FROM {2} {3}",
                                                 topCount > 0 ? "TOP("+topCount+")" : "",
                                                 fields,
                                                 tableName,
                                                 conditions.Length > 0 ? " WHERE " + conditions : "");

            SqlCeDataAdapter adapter = new SqlCeDataAdapter(selectCommand, ConnectionString);
            //SqlCeDataAdapter adapter = new SqlCeDataAdapter();
            //try
            //{
            //    adapter = new SqlCeDataAdapter(selectCommand, ConnectionString);
            //}
            //catch (Exception err)
            //{
            //    File.WriteAllText(@"error.txt", err.StackTrace);
            //    File.WriteAllText(@"error2.txt", selectCommand + " [*] " + ConnectionString);
            //}
            
            //File.WriteAllText(@"error2.txt", ConnectionString);
            //SqlCeDataAdapter adapter = new SqlCeDataAdapter(selectCommand, ConnectionString);
            
            DataSet dSet = new DataSet(tableName);
            adapter.Fill(dSet);
            dSet.Tables[0].TableName = tableName;

            //adapter.Dispose();
            return dSet.Tables[0];
        }

        public static DataTable GetTable(string selectCommand)
        {
            SqlCeDataAdapter adapter = new SqlCeDataAdapter(selectCommand, ConnectionString);
            DataSet dSet = new DataSet();
            adapter.Fill(dSet);
            
            return dSet.Tables[0];
        }

        public static DataView GetDataView2Tables(string tableName, string conditions = "", string fields = "*")
        {
            if (tableName == "Recipes_Convert")
            {
                return GetTable(tableName, fields, conditions).DefaultView;
            }

            DataTable table1 = GetTable(tableName, fields, conditions);
            DataTable table2 = GetTable("Recipes_Convert", fields, conditions);

            table1.Merge(table2);
            return table1.DefaultView;
        }

        public static string GetTableNameFromSlot(ItemPlaceViewModel.EquipmentSlots slot)
        {
            switch (slot)
            {
                case ItemPlaceViewModel.EquipmentSlots.Main:
                case ItemPlaceViewModel.EquipmentSlots.Armsfused:
                case ItemPlaceViewModel.EquipmentSlots.Sub:
                    return "Allitems_Weapons";

                case ItemPlaceViewModel.EquipmentSlots.Wing:
                    return "Allitems_Wings";
                    
                case ItemPlaceViewModel.EquipmentSlots.Head:
                    return "Allitems_Heads";
                    
                case ItemPlaceViewModel.EquipmentSlots.RightOrLeftEar:
                    return "Allitems_Ears";
                    
                case ItemPlaceViewModel.EquipmentSlots.Torso:
                    return "Allitems_Torsos";
                    
                case ItemPlaceViewModel.EquipmentSlots.Leg:
                    return "Allitems_Legs";
                    
                case ItemPlaceViewModel.EquipmentSlots.Foot:
                    return "Allitems_Foots";
                    
                case ItemPlaceViewModel.EquipmentSlots.Neck:
                    return "Allitems_Necks";
                    
                case ItemPlaceViewModel.EquipmentSlots.Shoulder:
                    return "Allitems_Shoulders";
                    
                case ItemPlaceViewModel.EquipmentSlots.Glove:
                    return "Allitems_Gloves";
                    
                case ItemPlaceViewModel.EquipmentSlots.RightOrLeftFinger:
                    return "Allitems_Fingers";
                    
                case ItemPlaceViewModel.EquipmentSlots.Waist:
                    return "Allitems_Waists";
                    
                default:
                    return "";
            }
        }

        public static ObservableCollection<DataRow> GetCoins(String itemName = "")
        {
            ObservableCollection<DataRow> coins = new ObservableCollection<DataRow>();

            DataTable table = GetTable("Allitems_Coins", "coin_name, coin_need, translate" + EngFix + " AS translate, icon_name", 
                                       string.Format("item_name = '{0}'", itemName));

            if (table.Rows.Count > 0)
            {
                foreach (DataRow row in table.Rows)
                {
                    coins.Add(row);
                }
            }
                
            return coins;
        }
        
    }

    public static class ClassFile
    {
        internal static string ShowSaveFileDialog(string fileName, string defExt, string filter, string initDir)
        {
            SaveFileDialog dlg = new SaveFileDialog
            {
                FileName = fileName,
                DefaultExt = defExt,
                Filter = filter,
                InitialDirectory = initDir
            };

            bool? result = dlg.ShowDialog();
            return result == true ? dlg.FileName : "";
        }

        internal static string ShowOpenFileDialog(string fileName, string defExt, string filter, string initDir)
        {
            OpenFileDialog dlg = new OpenFileDialog
            {
                FileName = fileName,
                DefaultExt = defExt,
                Filter = filter,
                InitialDirectory = initDir
            };

            bool? result = dlg.ShowDialog();
            return result == true ? dlg.FileName : "";
        }
    }
}
